package edu.vt.ece.rt.quorum.messsages.types;

import java.util.List;

import org.jgroups.Address;

import edu.vt.ece.rt.dstm.Context;
import edu.vt.ece.rt.dstm.ContextDelegator;
import edu.vt.ece.rt.dstm.QObject;
import edu.vt.ece.rt.quorum.ClustersManager;
import edu.vt.ece.rt.quorum.Resource;
import edu.vt.ece.rt.quorum.messsages.QMessage;
import edu.vt.ece.rt.quorum.messsages.QMessage.MessageType;
import edu.vt.ece.rt.util.Logger.Logger;

/*
 * Commit confirmation or Commit abortion request
 * @author Sudhanshu
 */

public class CommitConfirm extends QMessage implements Runnable {
	Context ct; 		//Specify the Context
	boolean commit;		//Specify read or write 

	public CommitConfirm(Context cxt, boolean c) {
		super(MessageType.CommitConfirm);
		ct = cxt;
		commit = c;
	}

	public void run() {
		
		synchronized (Resource.waitObj) {

			Context remoteContext = ct;
			Context localContext = ContextDelegator.getContext(ct.getContextId());
			
			if (commit) {
				
				Logger.debug("Commit Confirmed as Success "+ct.getContextId());
				localContext.setCommited();
				//			context.publishLocally();			//TODO: Think if require to check local copy
				if (localContext.isRoot()) {
					for(QObject obj: remoteContext.getWriteSet()) {

						obj.updateVersion();
						if (obj.getOwner() != 0) {
							Logger.debug("transaction working on other's object "+obj.getOwner()+ " "+remoteContext.getContextId());
						}
						Resource.updateObject(obj.getId(), obj);
						Resource.getQObject(obj.getId()).unlockObject(localContext.getContextId());	//Actually not required, as object is already replaced
						Logger.debug("Updated and Unlocked Object " + obj.getId() + " by tnx "+remoteContext.getContextId()+ " new owner is "+obj.getOwner());
					}

					for(QObject obj: remoteContext.getCreateSet()) {
						System.out.println("Published obj "+obj.getId());
						Resource.putQObject(obj.getId(), obj);
					}

				} else {
					Logger.debug("Skip updating objects inner transaction, replacing child by its parent in read/write set");
					/* replace transaction by its parent */
					Resource.replaceChild(localContext);
				}
//				ContextDelegator.removeContext(context);	
			} else {
				Logger.debug("Commit Confirmed as Abort "+ct.getContextId());

				ContextDelegator.getContext(localContext.getContextId()).setAborted();

				for(QObject obj: localContext.getWriteSet()) {
					Logger.debug("Aborted txn "+localContext.getContextId()+" trying to release lock on "+obj.getId());
					Resource.getQObject(obj.getId()).unlockObject(localContext.getContextId());
					if (localContext.parent!=null) {
						Resource.getQObject(obj.getId()).unlockObject(localContext.parent.getContextId());
					}
					Logger.debug("New owner for write obj "+obj.getId()+" is "+obj.getOwner());
					if (obj.getOwner() == localContext.getContextId()) {
						System.out.println("WTF for write "+localContext.getContextId()  +" on "+ClustersManager.baseClusterId);
					}
				}

				for(QObject obj: localContext.getReadSet()) {
					Logger.debug("Aborted txn "+localContext.getContextId()+" trying to release lock on "+obj.getId());
					Resource.getQObject(obj.getId()).unlockObject(localContext.getContextId());
					Logger.debug("New owner for read obj "+obj.getId()+" is "+obj.getOwner());
					if (obj.getOwner().longValue() == ct.getContextId()) {
						System.out.println("WTF for read "+localContext.getContextId()  +" on "+ClustersManager.baseClusterId);
					}
					if (localContext.parent!=null) {
						Resource.getQObject(obj.getId()).unlockObject(localContext.parent.getContextId());
					}

				}
				ContextDelegator.removeContext(ContextDelegator.getContext(ct.getContextId()));
			}
			Resource.rmFrLists(ContextDelegator.getContext(localContext.getContextId()));
		}
	}
}	

